using System;
using System.Collections.Generic;
using System.Text;

namespace Sandia.MVCFramework.Common
{
    /// <summary>
    /// A generic collection of tools used to work with arrays.
    /// </summary>
    /// <typeparam name="T">The type of array to work with.</typeparam>
    public class ArrayTools<T>
    {
        /// <summary>
        /// Compares the given arrays using the given IComparer.
        /// </summary>
        /// <param name="array1">The array to compare.</param>
        /// <param name="array2">The array to compare.</param>
        /// <param name="comparer">
        /// The IComparere to use to compare the elements of the array.
        /// </param>
        /// <returns>True if the arrays are equal, false otherwise.</returns>
        public static bool CompareArrays(
            T[] array1,
            T[] array2,
            IComparer<T> comparer)
        {
            if (array1.Length != array2.Length)
            {
                return false;
            }
            for (int i = 0; i < array1.Length; i++)
            {
                if (comparer.Compare(array1[i], array2[i]) != 0)
                {
                    return false;
                }
            }
            return true;
        }

        /// <summary>
        /// Compares the given arrays using the given IComparer to see if the
        /// first array is a proper subset of the second array.  So, every
        /// entry of the first must be found in the second.
        /// </summary>
        /// <param name="array1">
        /// The array to check is a proper subset of array2.
        /// </param>
        /// <param name="array2">
        /// The array to check if it fully contains array1.
        /// </param>
        /// <param name="comparer">
        /// The IComparere to use to compare the elements of the array.
        /// </param>
        /// <returns>
        /// True if array1 is a proper subset of array2, false otherwise.
        /// </returns>
        public static bool IsSubset(
            T[] array1,
            T[] array2,
            IComparer<T> comparer)
        {
            for (int i = 0; i < array1.Length; i++)
            {
                if (Search(array2, array1[i], comparer) < 0)
                {
                    return false;
                }
            }
            return true;
        }

        /// <summary>
        /// Gets the items in array2 that do not occur in array1.
        /// </summary>
        /// <param name="array1">The first array.</param>
        /// <param name="array2">The second array.</param>
        /// <param name="comparer">
        /// The IComparere to use to compare the elements of the array.
        /// </param>
        /// <returns>
        /// A list of items that occur in array2 that do not occur in array1.
        /// </returns>
        public static List<T> GetSubsetDifferences(
            T[] array1,
            T[] array2,
            IComparer<T> comparer)
        {
            List<T> results = new List<T>();

            for (int i = 0; i < array1.Length; i++)
            {
                if (Search(array2, array1[i], comparer) < 0)
                {
                    results.Add(array1[i]);
                }
            }

            return results;
        }

        /// <summary>
        /// An alternative to BinarySearch (which requires arrays to be sorted)
        /// </summary>
        /// <param name="array"></param>
        /// <param name="item"></param>
        /// <param name="comparer"></param>
        /// <returns></returns>
        public static int Search(T[] array, T item, IComparer<T> comparer)
        {
            // iterate through the target array until the item is found

            foreach (T targetItem in array)
            {
                if (comparer.Compare(targetItem, item) == 0)
                {
                    return 1;
                }
            }

            return -1; // not found
        }
    }
}
